#else
char opt_nmi[10] = "fatal";
#endif
+/*
+ * Comma-separated list of hexadecimal page numbers containing bad bytes.
+ * e.g. 'badpage=0x3f45,0x8a321'.
+ */
+char opt_badpage[100] = "";
static struct {
unsigned char *name;
enum { OPT_STR, OPT_UINT, OPT_BOOL } type;
void *var;
+ unsigned int len;
} opts[] = {
- { "console", OPT_STR, &opt_console },
- { "conswitch", OPT_STR, &opt_conswitch },
- { "com1", OPT_STR, &opt_com1 },
- { "com2", OPT_STR, &opt_com2 },
- { "dom0_mem", OPT_UINT, &opt_dom0_mem },
- { "noht", OPT_BOOL, &opt_noht },
- { "noacpi", OPT_BOOL, &opt_noacpi },
- { "nosmp", OPT_BOOL, &opt_nosmp },
- { "noreboot", OPT_BOOL, &opt_noreboot },
- { "ignorebiostables", OPT_BOOL, &opt_ignorebiostables },
- { "watchdog", OPT_BOOL, &opt_watchdog },
- { "pdb", OPT_STR, &opt_pdb },
- { "tbuf_size", OPT_UINT, &opt_tbuf_size },
- { "sched", OPT_STR, &opt_sched },
- { "physdev_dom0_hide", OPT_STR, &opt_physdev_dom0_hide },
- { "leveltrigger", OPT_STR, &opt_leveltrigger },
- { "edgetrigger", OPT_STR, &opt_edgetrigger },
- { "xenheap_megabytes", OPT_UINT, &opt_xenheap_megabytes },
- { "nmi", OPT_STR, &opt_nmi },
- { NULL, 0, NULL }
+#define V(_x) &_x, sizeof(_x)
+ { "console", OPT_STR, V(opt_console) },
+ { "conswitch", OPT_STR, V(opt_conswitch) },
+ { "com1", OPT_STR, V(opt_com1) },
+ { "com2", OPT_STR, V(opt_com2) },
+ { "dom0_mem", OPT_UINT, V(opt_dom0_mem) },
+ { "noht", OPT_BOOL, V(opt_noht) },
+ { "noacpi", OPT_BOOL, V(opt_noacpi) },
+ { "nosmp", OPT_BOOL, V(opt_nosmp) },
+ { "noreboot", OPT_BOOL, V(opt_noreboot) },
+ { "ignorebiostables", OPT_BOOL, V(opt_ignorebiostables) },
+ { "watchdog", OPT_BOOL, V(opt_watchdog) },
+ { "pdb", OPT_STR, V(opt_pdb) },
+ { "tbuf_size", OPT_UINT, V(opt_tbuf_size) },
+ { "sched", OPT_STR, V(opt_sched) },
+ { "physdev_dom0_hide", OPT_STR, V(opt_physdev_dom0_hide) },
+ { "leveltrigger", OPT_STR, V(opt_leveltrigger) },
+ { "edgetrigger", OPT_STR, V(opt_edgetrigger) },
+ { "xenheap_megabytes", OPT_UINT, V(opt_xenheap_megabytes) },
+ { "nmi", OPT_STR, V(opt_nmi) },
+ { "badpage", OPT_STR, V(opt_badpage) },
+ { NULL, 0, NULL, 0 }
};
{
case OPT_STR:
if ( opt != NULL )
- strcpy(opts[i].var, opt);
+ {
+ strncpy(opts[i].var, opt, opts[i].len);
+ ((char *)opts[i].var)[opts[i].len-1] = '\0';
+ }
break;
case OPT_UINT:
if ( opt != NULL )
#include <xen/slab.h>
#include <xen/irq.h>
+extern char opt_badpage[];
/*********************
* ALLOCATION BITMAP
unsigned long bitmap_start, unsigned long max_pages)
{
int i, j;
- unsigned long bitmap_size;
+ unsigned long bitmap_size, bad_pfn;
+ char *p;
memset(avail, 0, sizeof(avail));
/* All allocated by default. */
memset(alloc_bitmap, ~0, bitmap_size);
+ /*
+ * Process the bad-page list. Marking the page free in the bitmap will
+ * indicate to init_heap_pages() that it should not be placed on the
+ * buddy lists.
+ */
+ p = opt_badpage;
+ while ( *p != '\0' )
+ {
+ bad_pfn = simple_strtoul(p, &p, 0);
+
+ if ( *p == ',' )
+ p++;
+ else if ( *p != '\0' )
+ break;
+
+ if ( (bad_pfn < max_pages) && allocated_in_map(bad_pfn) )
+ {
+ printk("Marking page %08lx as bad\n", bad_pfn);
+ map_free(bad_pfn, 1);
+ }
+ }
+
return bitmap_start + bitmap_size;
}
/* Hand the specified arbitrary page range to the specified heap zone. */
void init_heap_pages(int zone, struct pfn_info *pg, unsigned long nr_pages)
{
- int i;
- unsigned long flags;
+ unsigned long i, pfn = page_to_pfn(pg);
- spin_lock_irqsave(&heap_lock, flags);
-
- /* Free up the memory we've been given to play with. */
- map_free(page_to_pfn(pg), nr_pages);
- avail[zone] += nr_pages;
-
- while ( nr_pages != 0 )
+ /* Process each page in turn, skipping bad pages. */
+ for ( i = 0; i < nr_pages; i++ )
{
- /*
- * Next chunk is limited by alignment of pg, but also must not be
- * bigger than remaining bytes.
- */
- for ( i = 0; i < MAX_ORDER; i++ )
- if ( ((page_to_pfn(pg) & (1 << i)) != 0) ||
- ((1 << (i + 1)) > nr_pages) )
- break;
-
- PFN_ORDER(pg) = i;
- list_add_tail(&pg->list, &heap[zone][i]);
-
- pg += 1 << i;
- nr_pages -= 1 << i;
+ if ( likely(allocated_in_map(pfn+i)) ) /* bad page? */
+ free_heap_pages(zone, pg+i, 0);
}
-
- spin_unlock_irqrestore(&heap_lock, flags);
}